Mise à jour le 07/12/2021
Créer une extension PHP

Créer une extension PHP

💣️N'étant pas du tout un expert sur le sujet, tout ce qui suit est à prendre avec des pincettes.

Voici un petit tutoriel pour créer une extension PHP (sous Debian).

1. Les ressources

Le site officiel de Zend(https://www.zend.com/resources/writing-php-extensions)
La page Github d'un squelette d'extension PHP(https://github.com/improved-php-library/skeleton-php-ext)


2. Exemple : création de la fonction PHP triple

Voici un exemple d'implémentation d'une nouvelle fonction, appelée `triple` qui retourne un entier multiplié par trois.

Ce code est à placer dans le fichier skeleton.c du projet skeleton-php-ext.

ZEND_BEGIN_ARG_INFO_EX(arginfo_triple, 0, 1, 0)
    ZEND_ARG_TYPE_INFO(0, str, IS_LONG, 1)
ZEND_END_ARG_INFO()

static const zend_function_entry functions[] = {
    PHP_FE(triple, arginfo_triple)
    PHP_FE_END
};

PHP_FUNCTION(triple)
{
    zend_long integer;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1)
        Z_PARAM_LONG(integer)
    ZEND_PARSE_PARAMETERS_END();

    RETVAL_LONG(integer*3);
}


Il faut également modifier le fichier php_skeleton.h pour ajouter le nom de la nouvelle fonction :

static PHP_FUNCTION(triple);


3. Exemple : création de la fonction PHP addition

Cela se complique un peu car nous allons créer maintenant une fonction avec deux arguments.

static const zend_function_entry functions[] = {
    PHP_FE(addition, arginfo_addition)
    PHP_FE_END
};

ZEND_BEGIN_ARG_INFO_EX(arginfo_addition, 0, 1, 0)
    ZEND_ARG_TYPE_INFO(0, a, IS_LONG, 1)
    ZEND_ARG_TYPE_INFO(0, b, IS_LONG, 1)
ZEND_END_ARG_INFO()

PHP_FUNCTION(addition)
{
    zend_long a;
    zend_long b;

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 2, 2)
        Z_PARAM_LONG(a)
        Z_PARAM_LONG(b)
    ZEND_PARSE_PARAMETERS_END();

    RETVAL_LONG(a+b);
}


Il faut également modifier le fichier php_skeleton.h pour ajouter le nom de la nouvelle fonction :

static PHP_FUNCTION(addition);


4. Exemple : création de la fonction PHP guessThenumber

La règle : l'utilisateur indique un nombre, si le nombre est plus grand que le nombre à deviner, la fonction retourne -1, si le nombre est le même, la fonction retourne 0, et si le nombre est plus petit, la fonction retourne 1.

📖️️L'idée de ce petit jeu provient de ce TP en C sur le site d'OpenClassRooms(https://openclassrooms.com/fr/courses/19980-apprenez-a-programmer-en-c/14828-tp-plus-ou-moins-votre-premier-jeu).


Pour cet exemple, on peut utiliser une variable globale qui sera initialisée qu'une seule fois par la fonction guessTheNumber.

ZEND_BEGIN_ARG_INFO_EX(arginfo_guessTheNumber, 0, 1, 0)
ZEND_END_ARG_INFO()

static const zend_function_entry functions[] = {
    PHP_FE(guessTheNumber, arginfo_guessTheNumber)
    PHP_FE_END
};

zend_long THE_NUMBER_TO_FIND;
PHP_FUNCTION(guessTheNumber)
{
    zend_long guess_long;

    if (!THE_NUMBER_TO_FIND) {
        THE_NUMBER_TO_FIND = rand() % 101;
    }

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1)
        Z_PARAM_LONG(guess_long)
    ZEND_PARSE_PARAMETERS_END();

    zend_long guessed_status;
    if (THE_NUMBER_TO_FIND > guess_long) {
        guessed_status = 1;
    } else if (THE_NUMBER_TO_FIND < guess_long) {
        guessed_status = -1;
    } else {
        guessed_status = 0;
    }

    RETVAL_LONG(guessed_status);
}
#endif


Il faut également modifier le fichier php_skeleton.h pour ajouter le nom de la nouvelle fonction :

static PHP_FUNCTION(guessTheNumber);


En pratique voilà ce que ça donnerait :

# php -a
php > var_dump(guessTheNumber(40));
int(-1)
php > var_dump(guessTheNumber(30));
int(-1)
php > var_dump(guessTheNumber(28));
int(0)
php > var_dump(guessTheNumber(28));
int(0)


On peut éventuellement faire un reset du nombre à trouver dès qu'il est trouvé pour que l'amusement perdure indéfiniment.

4.0.1 Création de la fonction C resetTheNumber

zend_long THE_NUMBER_TO_FIND;

void resetTheNumber()
{
    THE_NUMBER_TO_FIND = rand() % 101;
}

PHP_FUNCTION(resetTheNumber)
{
    resetTheNumber();
}

PHP_FUNCTION(guessTheNumber)
{
    zend_long guess_long;

    if (!THE_NUMBER_TO_FIND) {
        resetTheNumber();
    }

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 1)
        Z_PARAM_LONG(guess_long)
    ZEND_PARSE_PARAMETERS_END();

    zend_long guessed_status;
    if (THE_NUMBER_TO_FIND > guess_long) {
        guessed_status = 1;
    } else if (THE_NUMBER_TO_FIND < guess_long) {
        guessed_status = -1;
    } else {
        guessed_status = 0;
    }

    RETVAL_LONG(guessed_status);
}


5. Signatures des fonctions ZEND


Voici la signature de la fonction ZEND_PARSE_PARAMETERS_START_EX

define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args)